package com.midnight.rstar.controlller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.midnight.rstar.config.GlobalConfig;
import com.midnight.rstar.domain.NetResult;
import com.midnight.rstar.domain.Pair;
import com.midnight.rstar.domain.Result;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.hutool.core.io.FileUtil;

/**
 * @Author hanbo
 * @Since 2023/10/18
 */
@RestController
@RequestMapping("/res")
public class ResController {

    private static final ExecutorService executorService = Executors.newFixedThreadPool(4);
    @Autowired
    private Environment env;

    @Autowired
    private GlobalConfig globalConfig;
    @Autowired
    private ObjectMapper objectMapper;


    @RequestMapping("/query")
    public NetResult queryList(@RequestParam("md5s") List<String> md5s) {
        Map<String, Map<String, String>> globalJsonMap = globalConfig.getGlobalJsonMap();
        List<Map<String, String>> rs = new ArrayList<>();
        md5s.forEach(s -> {
            Map<String, String> tmp = globalJsonMap.get(s);
            if (tmp == null) {
                tmp = new HashMap<>();
                tmp.put("md5", s);
            }
            rs.add(tmp);
        });

        return NetResult.succ(rs, "ok");
    }

    @GetMapping("/test")
    public NetResult get() {
        return NetResult.succ("server run succed!");
    }

    @PostMapping("/save")
    public NetResult save(@RequestBody Result result) {
        if (result != null && result.getMd5() != null ) {
            synchronized (GlobalConfig.class) {
                Map<String, String> rs = globalConfig.getGlobalJsonMap().get(result.getMd5());
                if (rs == null) {
                    rs = new HashMap<>();
                    globalConfig.getGlobalJsonMap().put(result.getMd5(), rs);
                }

                if(result.getResultState().equals("2")&&result.getResultImg() != null && result.getResultDesc() != null){
                    rs.put("resultState", "2");
                    rs.put("resultDesc", result.getResultDesc());
                    rs.put("resultImage", getLocalIp() + result.getMd5() + "/" +result.getResultImg());
                    savaMapToFile();
                    return NetResult.succ(1, "save result succed");
                }else if (result.getResultState().equals("-1")) {
                    rs.put("resultState", "-1");
                    savaMapToFile();
                    return NetResult.succ(1, "save result succed");
                }
            }
        }
        return NetResult.fail(-1, "result params wrong or empty: " + result);
    }

    @PostMapping("/upload")
    public NetResult handleFileUpload(@RequestParam("file") MultipartFile file, @RequestParam("md5") String md5, @RequestParam("model") String model) {
        if (file.isEmpty() || md5 == null || md5.isEmpty()) {
            return NetResult.fail(-1, "file is empty or md5 is null.");
        }
        Map<String, String> rs;
        synchronized (GlobalConfig.class) {
            rs = globalConfig.getGlobalJsonMap().get(md5);
            if (rs != null) {
                return NetResult.succ(rs, "succ");
            } else {
                rs = new HashMap<>();
                globalConfig.getGlobalJsonMap().put(md5, rs);
            }
        }

        //保存文件
        Pair<String, File> pair = saveFileToServer(file, md5);
        if (pair == null) {
            return NetResult.fail(-3, "保存文件失败");
        }
        rs.put("md5", md5);
        rs.put("fileUrl", pair.getKey());

        //执行脚本
        excuteShell(md5, model, pair.getValue());

        return NetResult.succ(rs);

    }

    //保存文件，保存路径为root_path下。返回:1.远程访问路径 2.保存文件
    private Pair<String, File> saveFileToServer(MultipartFile file, String md5) {
        //获取文件原始名称
        String originalFilename = file.getOriginalFilename();
        //获取文件的类型
        String type = FileUtil.extName(originalFilename);
        //获取文件大小
        long size = file.getSize();
        String saveFileName = md5;
        if (type != null && !type.isEmpty()) {
            saveFileName = saveFileName + "." + type;
        }

        try {
            //文件存储的磁盘
            File uploadFile = new File(getRootPath() + md5, saveFileName);
            //判断文件目录是否存在
            if (!uploadFile.getParentFile().exists()) {
                //如果不存在就创建文件夹
                uploadFile.mkdirs();
            }
            file.transferTo(uploadFile);
            return new Pair(getLocalIp() + md5 + "/" + saveFileName, uploadFile);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    //todo 脚本路径
    private String scriptPath = "/home/QFRC/ZQS/Projects/YOLO_CV/yolov10-test/Inference_java.py";

    public void excuteShell(String md5, String model, File file) {
        // 在子线程中执行shell脚本
        executorService.submit(() -> {
            try {
                //直接执行shell命令
                //ProcessBuilder processBuilder = new ProcessBuilder("java", "--version", file.getAbsolutePath());
                //todo 执行指定脚本
                //ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", scriptPath, file.getAbsolutePath());
                ProcessBuilder processBuilder = new ProcessBuilder(
                        "/home/QFRC/ZQS/Anaconda/envs/yolov10/bin/python3",  // 使用 Python 3 运行
                        scriptPath,  // Python 脚本路径
                        md5,  // md5 参数
                        model,  //模型名称：yumi、fanqie
                        file.getAbsolutePath()  // 文件 参数
                );
                processBuilder.redirectErrorStream(true);

                Process process = processBuilder.start();
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

                String line;
                StringBuilder output = new StringBuilder("====hanbo===\n");
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }

                output.append("====hanbo-end===");

                System.out.println(output);

                int exitCode = process.waitFor();

                Map<String, String> rs;
                synchronized (GlobalConfig.class) {
                    rs = globalConfig.getGlobalJsonMap().get(md5);
                    if (rs == null) {
                        rs = new HashMap<>();
                        globalConfig.getGlobalJsonMap().put(md5, rs);

                    }
                    rs.put("shellCode", exitCode + "");
                    //rs.put("shellOutput", output.toString());

                    /*String jsonString = objectMapper.writeValueAsString(globalConfig.getGlobalJsonMap());
                    // 确保目录存在
                    if (!globalConfig.getConfigFile().exists() && !file.createNewFile()) {
                        throw new IOException("Unable to create file");
                    }*/

                    // 写入JSON字符串到文件
                    savaMapToFile();
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        });
    }


    private String localIp;

    private String getLocalIp() {
        if (localIp == null) {
            localIp = env.getProperty("local_ip");
        }
        return localIp;
    }

    private String rootPath;

    private String getRootPath() {
        if (rootPath == null) {
            rootPath = env.getProperty("root_path");
        }
        return rootPath;
    }

    //将内存数据写入到文件。
    private void savaMapToFile() {
        synchronized (GlobalConfig.class) {
            // 写入JSON字符串到文件
            Path path = Paths.get(globalConfig.getConfigFile().getAbsolutePath());
            try {
                objectMapper.writeValue(path.toFile(), globalConfig.getGlobalJsonMap());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
